#include "includes.h"



static int audio_fd;
static long long sum_nose = 0;

int audio_device_init()
{
	int ioctlParam;
	//write_i2cprogram();
	audio_fd = Open("/dev/dsp", O_RDWR);
	ioctlParam = SAMPLE_FREQ;		
	ioctl(audio_fd, SNDCTL_DSP_SPEED, &ioctlParam);		
	ioctlParam = 0x10;		
	ioctl(audio_fd, SNDCTL_DSP_SETFMT, &ioctlParam);		
	ioctlParam=10;		
	ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &ioctlParam );		
	ioctlParam=1;		
	ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &ioctlParam);			
	//ioctl(audiofd, SNDCTL_DSP_GETBLKSIZE, &ioctlParam );			
	//ioctl(audio_fd, 3629, 0);

	close(audio_fd);
	return 0;
}

int audio_read(short *sample_a, int power, int flag)
{
	unsigned int array_size;
	int ioctlParam;
	short *temp;
	int cnt = 0;
	int test = 0;
	int offsize;
	
	//int fdout;
	//int i;
	if (power > 31)
		return -1;
	
	if (flag == 1)
		offsize = 1000;
	else
		offsize = 0;
	
	array_size = 1<<power;
	temp = Malloc((array_size+offsize)*sizeof(short));
	//system("rm /St_host.wav");
	//fdout = Open("t_host.wav", O_WRONLY | O_CREAT, 0644);
	audio_fd = Open("/dev/dsp", O_RDWR);
	ioctlParam = SAMPLE_FREQ;		
	ioctl(audio_fd, SNDCTL_DSP_SPEED, &ioctlParam);		
	ioctlParam = 0x10;		
	ioctl(audio_fd, SNDCTL_DSP_SETFMT, &ioctlParam);		
	ioctlParam=10;		
	ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &ioctlParam );		
	ioctlParam=1;		
	//ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &ioctlParam);
	Readn(audio_fd, (void *)temp, (array_size+offsize)*sizeof(short));
	close(audio_fd);

	if (flag == 1)
	{
		for (cnt=0; cnt<offsize; cnt++)
		{
			test += temp[cnt];
			if (test != 0)
				break;
		}
	}

	memcpy(sample_a, &temp[cnt], array_size*sizeof(short));
	free(temp);
	//Writen(fdout, (void *)sample_a, array_size*sizeof(unsigned short));
	//close(fdout);
	return 0;
}

int audio_read_file(char *name, short *sample_a, int power)
{
	unsigned int array_size;
	//int i;
	int fd;
	if (power > 31)
		return -1;
	array_size = 1<<power;
	fd = Open(name, O_RDWR);
	lseek(fd, 44, SEEK_SET);
	Readn(fd,(void *)sample_a, array_size*sizeof(short));
	close(fd);
	//Writen(audio_fd, (void *)sample_a, array_size*sizeof(unsigned short));
	return 0;
}

/*
int audio_write(char *name, int power)
{
	unsigned int array_size;
	unsigned short *sample_a;
	int fd;
	if (power > 31)
		return -1;
	array_size = 1<<power;
	sample_a = Malloc(array_size*sizeof(unsigned short));
	fd = Open(name, O_RDWR);
	Readn(fd,(void *)sample_a, array_size*sizeof(unsigned short));
	Writen(audio_fd, (void *)sample_a, array_size*sizeof(unsigned short));
	close(fd);
	free(sample_a);
	return 0;
}
*/

int audio_write(char *name)
{
	char cmd[512];
	snprintf(cmd, sizeof(cmd), "aplay %s", name);
	printf("CMD <%s>\n", cmd);
	system(cmd);
	return 0;
}

int audio_noise_play()
{
	int i;
	int ioctlParam;
	short noise_sample[512];
	audio_fd = Open("/dev/dsp", O_RDWR);
	ioctlParam = SAMPLE_FREQ;		
	ioctl(audio_fd, SNDCTL_DSP_SPEED, &ioctlParam);		
	ioctlParam = 0x10;		
	ioctl(audio_fd, SNDCTL_DSP_SETFMT, &ioctlParam);		
	ioctlParam=10;		
	ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &ioctlParam );		
	ioctlParam=1;		
	ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &ioctlParam);
	
	bzero(noise_sample, ARRAY_SIZE(noise_sample)*sizeof(short));
	for (i=0; i<8; i++)
	{
		Writen(audio_fd, (void *)noise_sample, ARRAY_SIZE(noise_sample)*sizeof(short));
	}
	close(audio_fd);
	return 0;
}

/*
int cal_noise(int power)
{
	short *sample_a;
	int cnt;
	//long int *module_a;
	unsigned int array_size;
	long int temp;
	
	int i;
	struct compx *pstSeq_a;
	long nose[5];
	
	power = min(31, power);
	array_size = 1<<power;
	sample_a = (short *)Malloc(array_size*sizeof(short));
	pstSeq_a = Malloc(array_size*sizeof(struct compx));

	//module_a = Malloc(array_size*sizeof(long int));
	//bzero(module_a, array_size*sizeof(long int));
	for (cnt=0; cnt<5; cnt++)
	{
		bzero(sample_a, array_size*sizeof(short));
		bzero(pstSeq_a, array_size*sizeof(struct compx));
		nose[cnt] = 0;
		audio_read(sample_a, power);
		for (i=0; i<array_size; i++)
		{
			if (i<50 || i>array_size-50)
				printf("sample_a[%d] = %d\n", i, sample_a[i]);
			pstSeq_a[i].real = sample_a[i];
			pstSeq_a[i].imag = 0;
		}
		fft(power, pstSeq_a);
		for (i=1; i<array_size/2; i++)
		{
			temp = sqrt_ab(pstSeq_a[i].real, pstSeq_a[i].imag);
			nose[cnt] += temp*temp; 
		}
		printf("***********************************cnt %d, nose %ld\n", cnt, nose[cnt]);
		nose[cnt] = nose[cnt]/5;
	}

	for (cnt=0; cnt<5; cnt++)
		sum_nose += nose[cnt];
	printf("the sum nose is %lld\n", sum_nose);
	free(sample_a);
	free(pstSeq_a);
	return 0;
}
*/
long long get_nose_power()
{
	return sum_nose;
}

int set_nose_power(long long power)
{
	sum_nose = power;
	return 0;
}

int cal_noise(int power)
{
	short *sample_a;
	unsigned int array_size;
	volatile long int temp;	
	int i;
	int cnt;
	long long noise_power = 0;
	struct compx *pstSeq_a;
	
	power = min(31, power);
	array_size = 1<<power;
	sample_a = (short *)Malloc(array_size*sizeof(short));
	pstSeq_a = (struct compx *)Malloc(array_size*sizeof(struct compx));
	//for (cnt=0; cnt<5; cnt++)
	//{
		bzero(sample_a, array_size*sizeof(short));
		bzero(pstSeq_a, array_size*sizeof(struct compx));
		audio_read(sample_a, power, 0);

		for (i=0; i<array_size; i++)
		{
			pstSeq_a[i].real = sample_a[i];
			pstSeq_a[i].imag = 0;
		}

		fft(power, pstSeq_a);
		for (i=1; i<array_size/2; i++)
		{
			temp = sqrt_ab(pstSeq_a[i].real, pstSeq_a[i].imag);
			noise_power += temp*temp; 
		}

		set_nose_power(noise_power);
		printf("************the sum nose is %lld <-> %lld\n", noise_power, get_nose_power());
		
	//}
	free(sample_a);
	free(pstSeq_a);

/*
	for (cnt=0; cnt<5; cnt++)
	{
		printf("************noise_power[%d] = %lld\n", cnt, noise_power[cnt]);
	}
*/
	return 0;
}



int audio_analyse(PS_AUDIO_PAR pstAudio_par, short *sample_a, int power)
{
	//int freq;
	unsigned int array_size;
	//PS_AUDIO_PAR pstAudio_par;
	int pos = 0;
	//int test = 0;
	long int *module_a;
	long long sum_sig;
	long long sum_nos;
	long long sum_thd;
	volatile long int temp;
	long int max_module;
	long int level_module;
	//float power_s, power_n, power_x;
	float ratio;
	//int max_freq;
	int min_value;
	short max_sample;
	int left, right;
	int rank;
	struct compx *pstSeq_a;
	int i,j;
	
	if (power > 31)
		return -1;
	
	array_size = 1<<power;
	pstSeq_a = Malloc(array_size*sizeof(struct compx));
	bzero(pstSeq_a, array_size*sizeof(struct compx));
	module_a = Malloc(array_size*sizeof(long int));
	bzero(module_a, array_size*sizeof(long int));


	/*
	for (i=0; i<array_size; i++)
	{
		test += sample_a[i];
		if (test != 0)
			break;
	}
	printf("the not zeor is %d\n", i);
	*/

	
	max_sample = 0;
	for (i=0; i<array_size; i++)
	{
		pstSeq_a[i].real = sample_a[i];
		pstSeq_a[i].imag = 0;
		if (abs(sample_a[i]) > max_sample)
		{
			max_sample = abs(sample_a[i]);
		}
	}
	pstAudio_par->fr = max_sample * 0.707;
	printf("************the fr is %f\n", pstAudio_par->fr);

	
	if (fft(power, pstSeq_a) == -1)
		return -1;
	
	module_a[0] = sqrt_ab(pstSeq_a[0].real, pstSeq_a[0].imag);
	max_module = 0;
	for (i=1; i<=array_size/2; i++)
	{
		module_a[i] = sqrt_ab(pstSeq_a[i].real, pstSeq_a[i].imag);
		if (module_a[i] > max_module)
		{
			max_module = module_a[i];
			pos = i;
		}
	}

	level_module = max_module>>12;
	pstAudio_par->freq = (int) pos*((float)SAMPLE_FREQ/array_size);
	printf("************the frq is %d pos is %d\n", pstAudio_par->freq, pos);

/*
	freq = pstAudio->freq;
	max_freq = (int) pos*(SAMPLE_FREQ/array_size);
	if (abs(max_freq-freq) > 10)
	{
		err_msg("the main freq is wrong!!!");
		return -1;
	}
*/

	
	
	
	
	left = pos-1;
	right = pos+1;
	while(left>0 && module_a[left]>=level_module)
		left--;
	while(right<array_size/2 && module_a[right]>=level_module)
		right++;
	left++;
	right--;
	left = pos - min(10, abs(pos-left));
	right = pos + min(10, abs(pos-right));
	level_module = min(module_a[left], module_a[right]);
	printf("the level_module is %ld, the left is %d, the right is %d\n", level_module, left, right);


	rank = 0;
	while(max_module > PREC_CTRL)
	{
		max_module = max_module>>1;
		rank++;
	}

	sum_sig = 0;
	sum_nos = 0;
	for (i=left; i>0; i--)
	{
		if (module_a[i] < level_module)
		{
			temp = module_a[i]>>rank;
			sum_nos += temp*temp;
		}
	}
	for (i=right; i<array_size/2; i++)
	{
		if (module_a[i] < level_module)
		{
			temp = module_a[i]>>rank;
			sum_nos += temp*temp;
		}
	}
	for (i=left+1; i<right; i++)
	{
		temp = module_a[i]>>rank;
		sum_sig += temp*temp;
	}
	/*
	rank = 0;
	while(max_module > PREC_CTRL)
	{
		max_module = max_module>>1;
		rank++;
	}
	//level_module = level_module>>rank;
	//printf("*********rank = %d\n", rank);

	
	power_n = 0;
	power_s = 0;
	
	for (i=left; i>0; i--)
	{
		temp = module_a[i]>>rank;
		power_n += temp*temp;
	}
	for (i=right; i<=array_size/2; i++)
	{
		temp = module_a[i]>>rank;
		power_n += temp*temp;
	}
	for (i=left+1; i<right; i++)
	{
		temp = module_a[i]>>rank;
		power_s += temp*temp;
	}

	*/
	/*
	for (i=1; i<array_size/2; i++)
	{
		temp = module_a[i]>>rank;
		if (module_a[i] >= level_module)
		{
			power_s += temp*temp;
		}
		else
		{
			power_n += temp*temp;
		}
	}

	*/
	
	//printf("***********signal %f nosie %f\n", power_s, power_n);
	//pstAudio_par = &pstAudio->in_par;
	/*
	for (i=1; i<array_size/2; i++)
	{
		temp = module_a[i];
		sum_sig += temp*temp;
	}
	
	sum_nos = get_nose_power();
	*/
	if (sum_nos != 0)
	{
		ratio = (sum_sig/sum_nos) * 1.0;
		printf("sum_sig:%lld sum_nos:%lld ratio:%f\n", sum_sig, sum_nos, ratio);
		pstAudio_par->snr = 10*log10f(ratio);
		printf("***********analyse snr %f\n", pstAudio_par->snr);
	}
	else
	{
		pstAudio_par->snr = 100;
	}
	/*
	if (power_n !=0 )
		pstAudio_par->snr = 10*log10f(power_s/power_n);
	else
		pstAudio_par->snr = 10*log10f(power_s);
	printf("***********analyse snr %f\n", pstAudio_par->snr);
	*/
	
	//pstAudio_par->fr = 10*log10f(power_s/pstAudio->freq_power);
	/*
	temp = send_power>>rank;
	pstAudio_par->fr = 10*log10f(power_s/temp);
	printf("***********analyse fr %f\n", pstAudio_par->fr);
	*/
	
	sum_thd = 0;
	for (i=pos*2; i<array_size/2; i+=pos)
	{
		j = i-9;
		min_value = min(i+9, array_size/2);
		while(module_a[j]>level_module && j<=min_value)
		{
			temp = module_a[j]>>rank;
			sum_thd += temp*temp;
			j++;
		}
	}
	if (sum_thd != 0)
	{
		ratio = sum_sig/sum_thd;
		ratio = 1.0/ratio;
		pstAudio_par->thd = InvSqrt(ratio)*100;
	}
	else
		pstAudio_par->thd = 0;
	printf("sum_thd:%lld, sum_sig:%lld, ratio:%f\n", sum_thd, sum_sig, ratio);
	printf("***********analyse thd %f\n", pstAudio_par->thd);
	free(pstSeq_a);
	free(module_a);
	return 0;
	
}


